package spynx.desl.runtime.impl;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

import spynx.desl.runtime.IExecutionContext;

public class FindTextLocator extends AbstractTextLocator {

	public static final int OP_NOOP = 0;
	public static final int OP_EQUAL = 1;
	public static final int OP_CLOSE_TAG = 2;
	public static final int OP_MATCH = 3;
	
	protected Matcher matcher;
	protected Pattern regex;
	protected String matchedText;
	protected int length;
	
	public int getOperator() {
		Integer op = args.getArgument(context, "operator", OP_NOOP);
		return op;
	}
	
	public Pattern getPattern() {
		return regex != null ? regex :
			(regex = Pattern.compile(getPatternText(), Pattern.MULTILINE));
	}

	@Override
	public int locate(IExecutionContext context, int sidx, CharSequence input) {
		setContext(context);
		
		StringBuffer buffer = null;
		int result = -1;
		String value = getPatternText();
		length = 0;
		
		switch(getOperator()) {
		case OP_EQUAL:
			 buffer = new StringBuffer(input);
			 result = buffer.indexOf(value, sidx);
			 length = value.length();
			 matchedText = result >= 0 ? value : null;
			break;
		case OP_MATCH:
			matcher = getPattern().matcher(sidx > 0 ? input.subSequence(sidx, input.length()) : input);
			if (matcher.find()) {
				result = sidx + matcher.start();
				length = matcher.group().length();
				matchedText = matcher.group();
			}
			else
				matcher = null;
			break;
		case OP_CLOSE_TAG:
			String endtag = "</" + value + ">";
			String begtag = "<" + value;
			buffer = new StringBuffer(input);
			result = buffer.indexOf(endtag, sidx);
			while (result >= 0) {
				int begTagCount = 0;
				int tempSidx = sidx;
				while ((tempSidx = buffer.indexOf(begtag, sidx)) >= 0 && tempSidx < result) {
					begTagCount++;
					sidx = tempSidx + 1;
				}

				for (int i = 0; i < begTagCount && result >= 0; i++)
					result = buffer.indexOf(endtag, result + 1);

				if (begTagCount == 0) break;
			}

			length = endtag.length();
			matchedText = endtag; 
			break;
		}
		if (result == -1 && args.getArgument(context, "lastIndexOnFail", Boolean.FALSE))
			result = input.length();
		return result;
	}

	@Override
	public int getLength() {
		return length;
	}

	@Override
	public Object get(int fieldIdx) {
		if (fieldIdx == 0)
			return matchedText;
		else if (matcher != null)
			return matcher.group(fieldIdx);
		return null;
	}

	@Override
	public void set(int fieldIdx, Object value) {
		
	}
	
	@Override
	public Object get(String fieldname) {
		Integer fieldIdx = getFields().getArgument(getContext(), fieldname, -1);
		if (fieldIdx >= 0)
			return get(fieldIdx);
		throw new RuntimeException("Unknown field: " + fieldname);
	}

	@Override
	public void set(String fieldname, Object value) {
		
	}

}
